<script setup lang="ts">
import { ref, computed } from "vue"
import { PaginationProps, Tooltip } from "ant-design-vue"
import { useProvideButtonSize } from "@/components/button/context.ts"
import { PaginationParams, ClosuredDataSource, TableColumn } from "@/types"

import Table from "../table"

// 扩展ColumnType，否则column.description类型检测报错
declare module "ant-design-vue/es/table" {
  interface ColumnType {
    description?: string
  }
}

export type Props = {
  rowKey?: string
  datasource: ClosuredDataSource
  paginationShowTotal?: boolean
}

export type Slots = {
  operations(props?: any): any
  settings(props?: any): any
}

const columns = defineModel<TableColumn[]>("columns")

const props = defineProps<Props>()
const emits = defineEmits(["sortChange", "filtersChange"])

const slots = defineSlots<InstanceType<typeof Table>["$slots"] & Slots>()

// 给操作部分的button注入固定尺寸
useProvideButtonSize("sm")

// 需要传递给子组件的插件
const inheritedSlotKeys = Object.keys(slots).filter(
  (item) => !["operations", "settings"].includes(item),
)

// 分页参数
const paginationParams = defineModel<PaginationParams>("pagination", {
  required: false,
  default: { page: 1, size: 10 },
})

// 请求数据
const { isFetching, data, execute, error } = props.datasource(paginationParams)

const paginationResponse = computed<PaginationProps>(() => ({
  current: data.value?.page || 1,
  pageSize: data.value?.size || 10,
  total: data.value?.total || 0,
  showTotal: (total: number) => {
    if (props.paginationShowTotal) {
      return `共 ${total} 条`
    }
  },
}))

// 当分页发生变化的时候，执行请求
// 过滤和时抛出事件
function onChange(page: PaginationProps, _filters: any, sorter: any) {
  paginationParams.value.page = page?.current || 1
  paginationParams.value.size = page?.pageSize || 10

  // 清空已选择
  selectedRowKeys.value = []
  selected.value = []

  if (Object.keys(sorter).length) {
    // 如果是服务端排序，不调用execute
    if (
      !sorter.order ||
      (sorter.column && typeof sorter.column.sorter === "boolean")
    ) {
      emits("sortChange", sorter)
      return
    }
  }

  execute()
}

const selected = defineModel<any[]>("selected")

type Key = string | number
const selectedRowKeys = ref<Key[]>([])

function onSelectChange(keys: Key[]) {
  selectedRowKeys.value = keys
  selected.value = keys.map((key) =>
    data.value?.content.find((item: any) => item[props.rowKey!] === key),
  )
}

const rowSelection = computed(() => {
  if (props.rowKey) {
    return {
      selectedRowKeys: selectedRowKeys.value,
      onChange: onSelectChange,
    }
  }

  return undefined
})

function onClearSelected() {
  selectedRowKeys.value = []
  selected.value = []
}

defineExpose({
  pagination: paginationParams,
  isFetching,
  data,
  refresh: execute,
  error,
})
</script>

<template>
  <Table
    v-bind="$attrs"
    :row-key="rowKey"
    :loading="isFetching"
    :row-selection="rowSelection"
    :columns="columns"
    :dataSource="data?.content || []"
    :pagination="paginationResponse"
    class="pc-rest-table"
    @change="onChange"
  >
    <template #title>
      <div class="pc-flex pc-justify-between pc-items-end">
        <div class="pc-flex pc-gap-3 pc-items-center">
          <slot name="operations"></slot>
          <span class="selected-box" v-if="props.rowKey && selected?.length"
            >已选择{{ selected.length }}项<span
              class="pc-cursor-pointer text-color pc-ml-2"
              @click="onClearSelected"
              >清空</span
            ></span
          >
        </div>
        <div class="pc-flex pc-gap-3 pc-items-end">
          <slot name="settings"></slot>
        </div>
      </div>
    </template>
    <template #headerCell="{ column, title }">
      <div>
        {{ title }}
        <Tooltip
          v-if="column.description"
          :title="column.description"
          class="pc-mx-1"
        >
        </Tooltip>
      </div>
    </template>
    <template v-for="key in inheritedSlotKeys" :key="key" #[key]="params">
      <slot :name="key" :key="key" v-bind="params"></slot>
    </template>
  </Table>
</template>
<style scoped>
.selected-box {
  height: 22px;
  display: inline-block;
  line-height: 22px;
}
</style>
